# -*- coding: UTF-8 -*-

import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
from datetime import datetime, timedelta

import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
from plotly.utils import numpy

from dash_lib import analyse_data as analyse_lib
from dash_lib.mongodb_helper import single_insert_rate, get_rate_list, remove_rate

STAKE_COLOR = '#6C6C6C'
PROFIT_COLOR = '#629755'
YILED_COLOR = '#D5756C'

blog_name = '###'
app = dash.Dash()
app.css.append_css({
    'external_url': 'https://cdn.rawgit.com/plotly/dash-app-stylesheets/2d266c578d2a6e8850ebce48fdb52759b2aef506/stylesheet-oil-and-gas.css'})  # noqa: E501

tipper_list = analyse_lib.get_tipper_list()

day_range_list = []
stake_list = []
app.layout = html.Div([
    html.H4(id='title_tipper_name'),
    html.Div([
        html.Div([
            dcc.Dropdown(
                id='tipper_search',
                options=[{'label': i, 'value': i} for i in tipper_list],
                value=tipper_list[0]
            )],
            className='two columns',
        ),
        html.Div([
            dcc.DatePickerSingle(
                id='data_picker_range',
                date='2018-01-08',
            )],
            className='four columns',
        ),
        html.Div([
            dcc.RadioItems(
                id='date_pick_simple',
                labelStyle={'display': 'inline-block'},
                value=1000,
                options=[{'label': 'default', 'value': 1000},
                         {'label': 'last 3 m', 'value': 90},
                         {'label': 'last 1 m', 'value': 30},
                         {'label': 'last week', 'value': 7}]
            )],
            className='six columns',
        ),
    ],
        className='row'
    ),

    html.Div([
        html.Div([
            dcc.Dropdown(
                id='sport_cate',
            )],
            className='two columns',
        ),
        html.Div([
            dcc.RadioItems(
                id='pick_type',
                labelStyle={'display': 'inline-block'}
            )],
            className='two columns',
            style={'margin-top': '10'}

        ),
        html.Div([
            dcc.RadioItems(
                id='x_axis_type_radio',
                labelStyle={'display': 'inline-block'},
                value=0,
                options=[{'label': 'by time', 'value': 0},
                         {'label': 'by count', 'value': 1}]
            )],
            className='two columns',
            style={'margin-top': '10'}

        ),
        html.Div([
            dcc.Checklist(
                id='stake_selector',
                values=[],
                labelStyle={'display': 'inline-block'}

            )],
            style={'margin-top': '10'},
            className='six columns',
        ),
    ],
        className='row'
    ),
    dcc.Graph(id='indicator-graphic'),
    html.Div([
        dcc.Textarea(
            id='top_cate',
            placeholder='Enter a value...',
            value='',
            style={'width': '100%'}

        )
    ]),
    html.Div(id='base_info'),
    html.Div(id='sel_specity'),
    html.Div(id='btn_null'),
    html.H4(' rate select'),
    html.Div([
        dcc.Dropdown(
            id='rate_sport_cate',
        ),
        dcc.RadioItems(
            id='rate_pick_type',
            labelStyle={'display': 'inline-block'}
        ),
        dcc.RangeSlider(
            id='rate_stake_slider',
            min=1,
            max=10,
            marks={i: '{}'.format(i) for i in range(1,11)},
            value=[1, 5],
            allowCross=True,
        ),
        dcc.RadioItems(
            id='rate_score',
            style={'margin-top': '30'},
            value=5,
            labelStyle={'display': 'inline-block'},
            options=[{'label': 'A', 'value': 10},
                     {'label': 'B', 'value': 5}],

        ),

        html.Button('Submit', id='btn_add_rate', style={'margin-top': '30'}),
        html.Button('Remove Last', id='btn_remove_last', style={'margin-top': '30'}),

    ],
        className='row'
    ),

], style={'margin-bottom': '380', },
    className='ten columns offset-by-one'
)


def sort_df_order(dataframe, is_stake):
    if not dataframe.empty:
        dataframe['group_index'] = dataframe.index
        dataframe = dataframe[
            [('group_index', ''), ('len', 'profit'), ('mean', 'profit'), ('median', 'profit'), ('sum', 'profit'),
             ('amax', 'profit')]]
        dataframe.columns = ['stake' if is_stake else 'type', ' len', 'mean', 'median', 'sum', 'max']
        if not is_stake:
            cols = list(dataframe.columns.values)
            # print('dataframe.index.values', dataframe.index)
            # print('dataframe.columns.values', cols)
            # print(dataframe.type)
    return dataframe


def toast():
    print("#############!#!2731289371298371283")


def generate_table(dataframe, max_rows=10):
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +
        # Body
        [html.Tr([
            html.Td(dataframe.iloc[i][col], style={
                'background': '#fac1b7'
            }) for col in dataframe.columns
        ]) for i in range(min(len(dataframe), max_rows))]
    )


def log_df_test(df):
    base_pivot_table = pd.pivot_table(df, values=['profit'], index=['pick_type', 'sport', 'stake'],
                                      aggfunc=[len, np.mean, np.sum, np.median, np.max], fill_value=0, margins=False)
    unstack = base_pivot_table.unstack()
    # print(unstack.columns.values)
    # print(unstack)


@app.callback(
    Output('base_info', 'children'),
    [Input('tipper_search', 'value'),
     Input('sport_cate', 'value'),
     Input('pick_type', 'value'),
     Input('date_pick_simple', 'value'),
     Input('stake_selector', 'values'),
     Input('data_picker_range', 'date'),
     ])
def update_day_perfmance(tipper_search,
                         sport_cate, pick_type,
                         date_pick_simple,
                         stake_selector,
                         select_date):
    df = filter_dataframe(tipper_search,
                          sport_cate, pick_type,
                          date_pick_simple,
                          stake_selector,
                          select_date)
    base_pivot_table = pd.pivot_table(df, values=['profit'], index=['pick_type', 'sport', 'stake'],
                                      aggfunc=[len, np.mean, np.sum, np.median, np.max], fill_value=0, margins=False)

    SHOW_LIMIT = 14 if len(base_pivot_table.index) > 14 else len(base_pivot_table.index)
    base_info_df = base_pivot_table[base_pivot_table[('len', 'profit')] > SHOW_LIMIT]

    _pivot_table = pd.pivot_table(df, values=['profit'], index=['stake'],
                                  aggfunc=[len, np.mean, np.sum, np.median, np.max], fill_value=0, margins=False)
    stake_info_df = _pivot_table

    pivot_table = pd.pivot_table(df, values=['profit', 'stake'], index=['kickoff'],
                                 aggfunc={'profit': 'sum', 'stake': 'sum'}, fill_value=0, margins=False)
    SHOW_LIMIT = 14 if len(pivot_table.index) > 14 else len(pivot_table.index)

    lastest_day_df = pivot_table.tail(SHOW_LIMIT)
    lastest_day_df['yields'] = lastest_day_df['profit'] / lastest_day_df['stake'] * 100
    lastest_day_df = lastest_day_df.round(2)
    day_duration = ('DAY:   %s ==> %s     (days:%s ,count:%d)' %
                    (df['kickoff'].min(), df['kickoff'].max(), len(pivot_table['stake']), len(df['kickoff'])))
    return [
        html.H5(day_duration),

        html.Div([
            html.Div([
                generate_table(analyse_lib.round_df(sort_df_order(base_info_df, False))),

            ], className='six columns',
            ),
            html.Div(
                [generate_table(analyse_lib.round_df(sort_df_order(stake_info_df, True)))],
                className='six columns',
            )], className='row'),
        dcc.Graph(
            id='asd',
            figure={
                'data': [go.Bar(
                    y=lastest_day_df.stake,
                    text='stake', name='stake',

                ),
                    go.Scatter(
                        y=lastest_day_df.yields,
                        text='yield',
                        name='yield',
                        mode='lines+markers',
                        xaxis='x1',
                        yaxis='y2',
                        marker={
                            'size': 8,
                            'opacity': 0.5,
                            'line': {'width': 0.5, 'color': 'white'}
                        },
                        line=dict(
                            shape="spline",
                            smoothing=2,
                            width=1,
                            color=YILED_COLOR
                        )
                    )
                ],
                'layout': go.Layout(
                    xaxis={
                        'title': 'day perfermance',
                        'tickformat': '%y/%m/%d'

                    },
                    yaxis={
                        'title': '',
                    }, yaxis2={
                        'title': 'yield',
                        'side': 'right',
                        'overlaying': 'y'
                    }, )
            }
        )
    ]


@app.callback(
    Output('stake_selector', 'options'),
    [Input('tipper_search', 'value'),
     ])
def update_stake_selector(tipper_search):
    base_df = analyse_lib.init(tipper_search)
    # get stake list range
    base_df = base_df.sort_values(['stake'], ascending=[1])
    global stake_list
    stake_list = base_df['stake'].unique()
    return ([{'label': str(i), 'value': i} for i in stake_list])


@app.callback(
    Output('title_tipper_name', 'children'),
    [Input('tipper_search', 'value'),
     ])
def update_pick_type(tipper_search):
    return tipper_search


@app.callback(
    Output('sport_cate', 'options'),
    [Input('tipper_search', 'value'),
     Input('pick_type', 'value'),
     Input('date_pick_simple', 'value'),
     Input('stake_selector', 'values'),
     Input('data_picker_range', 'date'),
     ])
def update_sport(tipper_search,
                 pick_type,
                 date_pick_simple,
                 stake_selector,
                 select_date):
    base_df = filter_dataframe(tipper_search,
                               None, pick_type,
                               date_pick_simple,
                               stake_selector,
                               select_date)
    available_indicators = base_df['sport'].unique()
    available_indicators = numpy.concatenate([['All'], available_indicators])
    return [{'label': i, 'value': i} for i in available_indicators]


@app.callback(
    Output('pick_type', 'options'),
    [Input('tipper_search', 'value'),
     Input('sport_cate', 'value'),
     Input('date_pick_simple', 'value'),
     Input('stake_selector', 'values'),
     Input('data_picker_range', 'date'),
     ])
def update_pick_type(tipper_search,
                     sport_cate,
                     date_pick_simple,
                     stake_selector,
                     select_date):
    base_df = filter_dataframe(tipper_search,
                               sport_cate, None,
                               date_pick_simple,
                               stake_selector,
                               select_date)
    available_indicators_y = base_df['pick_type'].unique()
    available_indicators_y = numpy.concatenate([['All'], available_indicators_y])
    return [{'label': i, 'value': i} for i in available_indicators_y]


def filter_dataframe(tipper_search,
                     sport_cate, pick_type,
                     date_pick_simple,
                     stake_selector,
                     select_date):
    dff = analyse_lib.init(tipper_search)
    if pick_type and pick_type != 'All':
        dff = dff.query('pick_type==["' + pick_type + '"]')
    if sport_cate and sport_cate != 'All':
        dff = dff.query('sport==["' + sport_cate + '"]')
    if stake_selector:
        quert_stake_str = ''
        for i in range(len(stake_selector)):
            quert_stake_str += ' stake==' + str(stake_selector[i])
            if i < (len(stake_selector) - 1):
                quert_stake_str += ' or '
        dff = dff.query(quert_stake_str)

    start_date_str = select_date
    if len(dff.index) :
        if date_pick_simple:
            max_date = datetime.strptime(dff.kickoff.max(), '%Y-%m-%d')
            start_date = max_date.date() - timedelta(days=int(date_pick_simple))
            start_date_str = start_date.strftime('%Y-%m-%d')
        query_str = "kickoff>='" + start_date_str + "'"
        dff = dff.query(query_str)
    return dff


@app.callback(
    Output('indicator-graphic', 'figure'),
    [Input('tipper_search', 'value'),
     Input('sport_cate', 'value'),
     Input('pick_type', 'value'),
     Input('x_axis_type_radio', 'value'),
     Input('date_pick_simple', 'value'),
     Input('stake_selector', 'values'),
     Input('data_picker_range', 'date'),
     ])
def update_graph(tipper_search,
                 sport_cate, pick_type, x_axis_type_radio,
                 date_pick_simple,
                 stake_selector,
                 select_date):
    dff = filter_dataframe(tipper_search,
                           sport_cate, pick_type,
                           date_pick_simple,
                           stake_selector,
                           select_date)
    dff = analyse_lib.analyse(dff)
    return {
        'data': [go.Scatter(
            x=None if x_axis_type_radio else dff.days,
            y=dff.profit,
            text='profit',
            name='profit',
            mode='lines+markers',
            marker=dict(symbol='diamond-open'),
            line=dict(
                shape="spline",
                smoothing=2,
                width=1,
                color=PROFIT_COLOR
            ),
        ),
            go.Scatter(
                x=None if x_axis_type_radio else dff.days,
                y=dff.stake,
                text='stake', name='stake',
                mode='lines+markers',
                marker=dict(symbol='diamond-open'),
                line=dict(
                    shape="spline",
                    smoothing=2,
                    width=1,
                    color=STAKE_COLOR
                ),
            ),
            go.Scatter(
                x=None if x_axis_type_radio else dff.days,
                y=dff.yields,
                text='yield',
                name='yield',
                mode='lines+markers',
                xaxis='x1',
                yaxis='y2',
                marker={
                    'size': 8,
                    'opacity': 0.5,
                    'line': {'width': 0.5, 'color': 'white'}
                },
                line=dict(
                    shape="spline",
                    smoothing=2,
                    width=1,
                    color=YILED_COLOR
                )
            )
        ],
        'layout': go.Layout(
            xaxis={
                'title': 'main',
                'tickformat': '%y/%m/%d'

            },
            yaxis={
                'title': 'y1',
            },
            yaxis2={
                'title': 'yield',
                'side': 'right',
                'overlaying': 'y'
            },
            margin={'l': 40, 'b': 80, 't': 40, 'r': 0},
            hovermode='x',

        )
    }


@app.callback(
    Output('rate_sport_cate', 'options'),
    [Input('tipper_search', 'value'),
     ])
def update_rate_sport(tipper_search):
    base_df = analyse_lib.init(tipper_search)
    available_indicators = base_df['sport'].unique()
    available_indicators = numpy.concatenate([['All'], available_indicators])
    return [{'label': i, 'value': i} for i in available_indicators]


@app.callback(
    Output('rate_pick_type', 'options'),
    [Input('tipper_search', 'value')
     ])
def update_rate_pick_type(tipper_search):
    base_df = analyse_lib.init(tipper_search)
    available_indicators_y = base_df['pick_type'].unique()
    available_indicators_y = numpy.concatenate([['All'], available_indicators_y])
    return [{'label': i, 'value': i} for i in available_indicators_y]


@app.callback(
    Output('rate_stake_slider', 'value'),
    [Input('tipper_search', 'value')
     ])
def reset_check_vlue(tipper_search):
    return [0, 5]


last_n_clcik = None
last_n_remove_clcik = None


@app.callback(
    dash.dependencies.Output('btn_null', 'children'),
    [dash.dependencies.Input('btn_add_rate', 'n_clicks'),
     dash.dependencies.Input('btn_remove_last', 'n_clicks'),
     dash.dependencies.Input('tipper_search', 'value')],
    [
        dash.dependencies.State('rate_pick_type', 'value'),
        dash.dependencies.State('rate_sport_cate', 'value'),
        dash.dependencies.State('rate_stake_slider', 'value'),
        dash.dependencies.State('rate_score', 'value')
    ]
)
def update_output(n_clicks, n_remove_clicks, rate_tipper_value, rate_pick_type, rate_sport_cate, rate_stake_slider,
                  rate_score):
    print('n_clicks ==========', n_clicks)
    global last_n_clcik, last_n_remove_clcik
    if n_clicks != last_n_clcik:
        single_insert_rate(rate_tipper_value, rate_sport_cate, rate_pick_type, rate_stake_slider, rate_score)
    last_n_clcik = n_clicks
    if n_remove_clicks != last_n_remove_clcik:
        remove_rate(rate_tipper_value)
    last_n_remove_clcik = n_remove_clicks

    return html.Table(
        # Body
        [html.Tr([
            html.Td(row['tipper'], style={
                'background': '#fac1b7'
            }),
            html.Td(row['sport'], style={
                'background': '#fac1b7'
            }),
            html.Td(row['pick_type'], style={
                'background': '#fac1b7'
            }),
            html.Td(str(row['stake'][0]) + ' - ' + str(row['stake'][1]), style={
                'background': '#fac1b7'
            }),
            html.Td(row['score'], style={
                'background': '#fac1b7'
            })
        ]) for row in get_rate_list(rate_tipper_value)]
    )


if __name__ == '__main__':
    app.run_server(debug=True, port=8051)
